﻿/*
 * Twipler - Twitter Web Client with features.
 *  
 *  Copyright (C) 2010. Ian Quigley
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details. 
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Twipler.App.Parse.Html;
using Twipler.App.Render.Tree;
using Twipler.Data.Entity.Theme;
using Twipler.Data.Entity.Twipler;
using Environment=Twipler.App.Machine.Environment;
using System.IO;

namespace Twipler.App.Render
{

    public class PageProducer
    {
        private readonly string _pageKey;
        private AbstractItem _root;
        public Machine.Environment MachineEnvironment = new Environment();
        public string Name;

        private PageProducer(int themeId, string pageName, AbstractItem root)
        {
            _pageKey = FormatPageKey(themeId, pageName);
            _root = root;
            Name = pageName;
        }

        public override string ToString()
        {
            return "PageProducer[" + Name + "]";
        }
        public static PageProducer Get(Uri uri)
        {
            if ((Current.Visitor.IsAnonymous) || (Current.Visitor.Design == null))
                return null;

            string filename = GetFilename(uri);
            if (filename == null)
                return null;

            PageProducer producer = Current.PageProducer;
            if ((producer != null) && (producer.IsForPage(Current.Visitor.Design.Id, filename)))
                return producer;

            string pageTemplate;
            List<Container> containers = Current.Visitor.Design.FindContainer(filename);
            if (containers.Count() == 0)
                pageTemplate = Current.Visitor.Design.FirstPage.Source;
            else
                pageTemplate = containers[0].Source;

            AbstractItem root = (new Template(pageTemplate)).Parse();

            producer = new PageProducer(Current.Visitor.Design.Id, filename, root);
            Current.PageProducer = producer;

            return producer;
        }
                
        public void Render(HttpResponse response)
        {
            Current.StylesheetProducer.ReactToChange();
            
            StringBuilder html = new StringBuilder();
            _root.Render(html, MachineEnvironment);
            response.Write(html.ToString());
        }

        public void Postback(HttpRequest request)
        {
			// Execute any OnPostback items
			ForEachRenderItem(item => { if (item is OnPostbackItem) item.Postback(MachineEnvironment); });

            string postbackId = GetPostbackId(request);
            if (String.IsNullOrEmpty(postbackId))
                return;


        	ForEachRenderItem( item => {
        				if (item.PostbackId.Equals(postbackId, StringComparison.OrdinalIgnoreCase))
        					item.Postback(MachineEnvironment);
        				});

        }

        public AbstractItem FindByPostbackId(string postbackId)
        {
			AbstractItem anyMatch = null;
        	
			ForEachRenderItem(
        		item => { if (item.PostbackId.Equals(postbackId, StringComparison.OrdinalIgnoreCase)) anyMatch = item; });

        	return anyMatch;
        }

        private bool IsForPage(int themeId, string pageName)
        {
            return this._pageKey == FormatPageKey(themeId, pageName);
        }

        private static string FormatPageKey(int themeId, string pageName)
        {
            return string.Format("{0}-{1}", themeId, pageName);
        }

        private static string GetFilename(Uri uri)
        {
            string filename = uri.Segments.Last();
            return filename.IndexOf('.') == -1 ? null : filename.Substring(0, filename.IndexOf('.'));
        }

        private string GetPostbackId(HttpRequest request)
        {
            return request.Form["PostbackId"] ?? string.Empty;
        }

		private void ForEachRenderItem(Action<AbstractItem> action)
		{
			ForEachRenderItem(action, _root.Children);
		}
		
		private static void ForEachRenderItem(Action<AbstractItem> action, IEnumerable<AbstractItem> childrenList)
		{
			if ((childrenList == null) || !childrenList.Any())
				return;

			foreach (AbstractItem item in childrenList)
			{
				action(item);
				ForEachRenderItem(action, item.Children);
			}
		}
    }
}
